/*MyPhotoIndex Free Photo Organizer <www.myphotoindex.com>
  Copyright (C) <2006-2010>  <Asaf Yarkoni asaf@yarkoni.net>

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.*/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Reflection;
using System.IO;
using System.Drawing;
using MyPhotoIndex.Interfaces;
using System.Net.Mail;
using System.Collections.ObjectModel;
using System.Web;
using System.Threading;
using MyPhotoIndex.Plugins.Share.Flickr.Properties;
using MyPhotoIndex.Utilities;
using System.Drawing.Imaging;
using MyPhotoIndex.Plugins.ImageFormatProviders;
using MyPhotoIndex.Plugins.Share.Flickr;
using MyPhotoIndex.Interfaces.Plugins;
using MyPhotoIndex.Interfaces.Imaging;
using MyPhotoIndex.Interfaces.ImageFormatProviders;
using MyPhotoIndex.Interfaces.Tagging;

namespace MyPhotoIndex.Plugins.Mail
{
    public class FlickerPlugin : ISharePlugin
    {
        private IApplicationContext m_applicationContext;
        private System.Drawing.Size m_imageSize;
        private int m_progressValue;
        private Semaphore m_semaphore = new Semaphore(1, 1);

        const string apiKey = "14c4c819dc7a3ee328912bcee52cbdc6";
        const string sharedSecret = "76aab061a6d1f534";

        static string ms_frob;
        static Auth ms_auth;

        public override string ToString()
        {
            return Name;
        }

        #region Mail Members

        public void Send(ReadOnlyCollection<IImageData> imageFiles, System.Drawing.Size imageSize)
        {
            m_imageSize = imageSize;

            if (ms_auth == null)
            {
                Authenticate();
            }

            if (ms_auth == null)
            {
                return;
            }

            ThreadPool.QueueUserWorkItem(new WaitCallback(SendAsync), imageFiles);
        }

        void SendAsync(Object state)
        {
            ReadOnlyCollection<IImageData> imageFiles = state as ReadOnlyCollection<IImageData>;

            m_applicationContext.ProcessProgress.IsInfinite = true;
            m_applicationContext.ProcessProgress.ProcessDescription = this.ToString();
            m_applicationContext.ProcessProgress.Running = true;

            Dictionary<string, string> files = PrepareFilesForUpload(imageFiles);

            int totalSize = 0;
            foreach (string file in files.Values)
            {
                FileInfo fi = new FileInfo(file);
                totalSize += (int)fi.Length;
            }

            m_applicationContext.ProcessProgress.Running = false;

            m_progressValue = 0;
            m_applicationContext.ProcessProgress.Maximum = totalSize;
            m_applicationContext.ProcessProgress.IsInfinite = false;
            m_applicationContext.ProcessProgress.ProcessDescription = this.ToString();
            m_applicationContext.ProcessProgress.Running = true;

            foreach (IImageData imageData in imageFiles)
            {
                string tempFileName = string.Empty;
                if (files.TryGetValue(imageData.FileName, out tempFileName) == true)
                {
                    m_semaphore.WaitOne();
                    m_applicationContext.ProcessProgress.ProcessDescription = this.ToString() + " - " + Path.GetFileName(imageData.FileName);
                    SendOneImage(imageData, tempFileName);
                }
            }

            m_applicationContext.ProcessProgress.Running = false;
        }

        private Dictionary<string, string> PrepareFilesForUpload(ReadOnlyCollection<IImageData> imageFiles)
        {
            Dictionary<string, string> files = new Dictionary<string, string>();
            foreach (IImageData imageData in imageFiles)
            {
                string tempFile = Path.GetRandomFileName();
                tempFile = Path.ChangeExtension(tempFile, "Jpg");
                tempFile = Path.Combine(Path.GetTempPath(), tempFile);

                using (Image image = imageData.FormatProvider.LoadImage(imageData, m_imageSize))
                {
                    if (image != null)
                    {
                        IImageFormatProvider jpgProvider = ImageFormatProviders.ImageFormatProviders.Default["jpg"];
                        jpgProvider.SaveImage(image, imageData, tempFile);

                        files.Add(imageData.FileName, tempFile);
                    }
                }
            }

            return files;
        }

        void SendOneImage(IImageData imageData, string fileName)
        {
            try
            {
                Flickr flickr = new Flickr(apiKey, sharedSecret, ms_auth.Token);

                string title = Path.GetFileName(imageData.FileName);
                string description = imageData.Comment;
                string tags = string.Empty;

                foreach (int tagId in imageData.Tags)
                {
                    IImageTag imageTag = m_applicationContext.ImageTagCollection.GetTag(tagId);
                    if (imageTag != null)
                    {
                        tags += imageTag.Name + ",";
                    }
                }

                flickr.UploadProgress += new EventHandler<UploadProgressEventArgs>(flickr_OnUploadProgress);
                string photoId = flickr.UploadPicture(fileName, title, description, tags, 
                    FlickrPluginSettings.Default.IsPublic,
                    FlickrPluginSettings.Default.IsFamily,
                    FlickrPluginSettings.Default.IsFriend);
                File.Delete(fileName);
            }
            catch (Exception ex)
            {
                Logger.Log(ex);
            }
            finally
            {
                m_semaphore.Release();
            }
        }

        void flickr_OnUploadProgress(object sender, UploadProgressEventArgs e)
        {
            m_progressValue += e.Bytes;
            m_applicationContext.ProcessProgress.Value = m_progressValue;
            Application.DoEvents();
        }

        private void Authenticate()
        {
            m_applicationContext.ProcessProgress.ProcessDescription = this.ToString() + " Authenticating";
            m_applicationContext.ProcessProgress.IsInfinite = true;
            m_applicationContext.ProcessProgress.Running = true;

            Flickr flickr = new Flickr(apiKey, sharedSecret);
            try
            {
                ms_frob = flickr.AuthGetFrob();


                string flickrUrl = flickr.AuthCalcUrl(ms_frob);

                Browser browserForm = new Browser(flickrUrl);
                DialogResult dr = browserForm.ShowDialog();
                if (dr == DialogResult.Cancel)
                {
                    m_applicationContext.ProcessProgress.Running = false;
                    return;
                }

                ms_auth = flickr.AuthGetToken(ms_frob);
            }
            catch (Exception ex)
            {
                Logger.Log(ex);
                m_applicationContext.ProcessProgress.Running = false;
                return;
            }

            m_applicationContext.ProcessProgress.Running = false;
        }

        #endregion

        #region Plugin Members

        public bool Load(IApplicationContext applicationContext)
        {
            m_applicationContext = applicationContext;
            FlickrPluginSettings.SettingsManager = m_applicationContext.SettingsManager;

            FlickrPluginSettings settings = FlickrPluginSettings.Default;
            return true;
        }

        public string Name
        {
            get { return "Flickr"; }
        }

        public void Unload()
        {

        }

        #endregion

        #region IMailPlugin Members

        public void AddRecipient(MailAddress address){}

        public bool RequireRecipients
        {
            get { return false; }
        }

        #endregion

        #region IMailPlugin Members

        public Image Icon
        {
            get { return Resources.FlickerIcon; }
        }

        #endregion

        #region IPlugin Members

        public string Description
        {
            get { return Name; }
        }

        #endregion
    }
}
